package org.apache.lucene.index;

import java.io.IOException;

import org.apache.lucene.store.IndexInput;
import org.apache.lucene.util.BitVector;

public class TagBlockTermDocs {
  private FieldInfos fieldInfos;
  private IndexInput stream;
  private int doc;
  protected int count;
  private long basePointer;
  private long skipPointer;
  private BitVector deletedDocs;
  protected int numDocs;
  private TagBlockSkipListReader skipListReader;
  boolean haveSkipped;
  private int skipInterval;
  private int maxSkipLevels;
  private int blockNum;
  
  public TagBlockTermDocs(int blockNum, TagBlockInfos tagBlockInfos, BitVector deletedDocs, IndexInput stream, int skipInterval, int maxSkipLevels) throws IOException {
    this.blockNum = blockNum;
    this.deletedDocs = deletedDocs;
    this.stream = stream;
    this.skipInterval = skipInterval;
    this.maxSkipLevels = maxSkipLevels;
    seek(tagBlockInfos, blockNum);
  }
  
  public final int doc() {
    return doc;
  }
  
  private void seek(TagBlockInfos tagBlockInfos, int blockNum) throws IOException {
    count = 0;
    doc = 0;
    this.blockNum = blockNum;
    numDocs = tagBlockInfos.docFreqs[blockNum];
    basePointer = tagBlockInfos.positions[blockNum];
    stream.seek(basePointer);
    int skipOffset = stream.readVInt();
    skipPointer = skipOffset + basePointer;
    
    haveSkipped = false;
  }
  
  public boolean skipTo(int target) throws IOException {
    if (numDocs >= skipInterval) { 
      if (skipListReader == null)
        skipListReader = new TagBlockSkipListReader((IndexInput) stream.clone(), maxSkipLevels, skipInterval);                                                                                                                  
      if (!haveSkipped) { 
        skipListReader.init(skipPointer, basePointer, numDocs);
        haveSkipped = true;
      }
      int newCount = skipListReader.skipTo(target);
      if (newCount > count) {
        // TODO: make sure pointer is relative stream, probably is not
        stream.seek(skipListReader.getPointer());
        doc = skipListReader.getDoc();
        count = newCount;
      }
    }
    do {
      if (!next())
        return false;
    } while (target > doc);
    return true;
  }
  
  public int read(final int[] docs, final int[] freqs) throws IOException {
    final int length = docs.length;
    int i = 0;
    while (i < length && count < numDocs) {
      final int docCode = stream.readVInt();
      doc += docCode >>> 1; // shift off low bit
      count++;
      if (deletedDocs == null || !deletedDocs.get(doc)) {
        docs[i] = doc;
        freqs[i] = 1;
        ++i;
      }
    }
    return i;
  }
  
  public boolean next() throws IOException {
    while (true) {
      if (count == numDocs)
        return false;
      int docCode = stream.readVInt();
      doc += docCode >>> 1; // shift off low bit
      count++;
      if (deletedDocs == null || !deletedDocs.get(doc))
        break;
    }
    return true;
  }
  
  public void close() throws IOException {
    stream.close();
    if (skipListReader != null)
      skipListReader.close();
  }
}
